﻿using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace System.Web.Mvc
{
	public static partial class Holovacs
	{
		public static HtmlString SelectFor<TModel, TProperty, TListItem>(
			this HtmlHelper<TModel> htmlHelper,
			Expression<Func<TModel, TProperty>> expression,
			IEnumerable<TListItem> enumeratedItems,
			string idPropertyName,
			string displayPropertyName,
			string titlePropertyName,
			object htmlAttributes) where TModel : class
		{
			//initialize values
			var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
			var propertyName = metaData.PropertyName;
			var propertyValue = htmlHelper.ViewData.Eval(propertyName).ToStringOrEmpty();
			var enumeratedType = typeof(TListItem);

			//build the select tag
			var returnText = string.Format("<select id=\"{0}\" name=\"{0}\"", HttpUtility.HtmlEncode(propertyName));
			if (htmlAttributes != null)
			{
				foreach (var kvp in htmlAttributes.GetType().GetProperties()
				 .ToDictionary(p => p.Name, p => p.GetValue(htmlAttributes, null)))
				{
					returnText += string.Format(" {0}=\"{1}\"", HttpUtility.HtmlEncode(kvp.Key),
					 HttpUtility.HtmlEncode(kvp.Value.ToStringOrEmpty()));
				}
			}
			returnText += ">\n";

			//build the options tags
			foreach (TListItem listItem in enumeratedItems)
			{
				var idValue = enumeratedType.GetProperties()
				 .FirstOrDefault(p => p.Name == idPropertyName)
				 .GetValue(listItem, null).ToStringOrEmpty();
				var titleValue = enumeratedType.GetProperties()
				 .FirstOrDefault(p => p.Name == titlePropertyName)
				 .GetValue(listItem, null).ToStringOrEmpty();
				var displayValue = enumeratedType.GetProperties()
				 .FirstOrDefault(p => p.Name == displayPropertyName)
				 .GetValue(listItem, null).ToStringOrEmpty();
				returnText += string.Format("<option value=\"{0}\" title=\"{1}\"",
				 HttpUtility.HtmlEncode(idValue), HttpUtility.HtmlEncode(titleValue));
				if (idValue == propertyValue)
				{
					returnText += " selected=\"selected\"";
				}
				returnText += string.Format(">{0}</option>\n", displayValue);
			}

			//close the select tag
			returnText += "</select>";
			return new HtmlString(returnText);
		}

		public static HtmlString SelectFor<TModel, TProperty, TListItem>(
			this HtmlHelper<TModel> htmlHelper,
			Expression<Func<TModel, TProperty>> expression,
			IEnumerable<TListItem> enumeratedItems,
			string idPropertyName,
			string displayPropertyName,
			string titlePropertyName) where TModel : class
		{
			return htmlHelper.SelectFor(
				expression,
				enumeratedItems,
				idPropertyName,
				displayPropertyName,
				titlePropertyName,
				null);
		}

		public static HtmlString SelectFor<TModel, TProperty, TListItem>(
			this HtmlHelper<TModel> htmlHelper,
			Expression<Func<TModel, TProperty>> expression,
			IEnumerable<TListItem> enumeratedItems,
			string idPropertyName,
			string displayPropertyName) where TModel : class
		{
			return htmlHelper.SelectFor(
				expression,
				enumeratedItems,
				idPropertyName,
				displayPropertyName,
				displayPropertyName,
				null);
		}

		public static HtmlString SelectFor<TModel, TProperty, TListItem>(
			this HtmlHelper<TModel> htmlHelper,
			Expression<Func<TModel, TProperty>> forExpression,
			IEnumerable<TListItem> enumeratedItems,
			Property<TListItem> idExpression,
			Property<TListItem> displayExpression,
			Property<TListItem> titleExpression,
			object htmlAttributes,
            bool blankFirstLine) where TModel : class
		{
			//initialize values
			var metaData = ModelMetadata.FromLambdaExpression(forExpression, htmlHelper.ViewData);
			var propertyName = metaData.PropertyName;
			var propertyValue = htmlHelper.ViewData.Eval(propertyName).ToStringOrEmpty();
			var enumeratedType = typeof(TListItem);

			//build the select tag
			var returnText = string.Format("<select id=\"{0}\" name=\"{0}\"", HttpUtility.HtmlEncode(propertyName));
			if (htmlAttributes != null)
			{
				foreach (var kvp in htmlAttributes.GetType().GetProperties()
				 .ToDictionary(p => p.Name, p => p.GetValue(htmlAttributes, null)))
				{
					returnText += string.Format(" {0}=\"{1}\"", HttpUtility.HtmlEncode(kvp.Key),
					 HttpUtility.HtmlEncode(kvp.Value.ToStringOrEmpty()));
				}
			}
			returnText += ">\n";

            if (blankFirstLine)
            {
                returnText += "<option value=\"\"></option>";
            }

			//build the options tags
			foreach (TListItem listItem in enumeratedItems)
			{
				var idValue = idExpression(listItem).ToStringOrEmpty();
                var displayValue = displayExpression(listItem).ToStringOrEmpty();
                var titleValue = titleExpression(listItem).ToStringOrEmpty();
				returnText += string.Format("<option value=\"{0}\" title=\"{1}\"",
					HttpUtility.HtmlEncode(idValue), HttpUtility.HtmlEncode(titleValue));
				if (idValue == propertyValue)
				{
					returnText += " selected=\"selected\"";
				}
				returnText += string.Format(">{0}</option>\n", HttpUtility.HtmlEncode(displayValue));
			}

			//close the select tag
			returnText += "</select>";
			return new HtmlString(returnText);
		}

        public static HtmlString SelectForWithBlankLine<TModel, TProperty, TListItem>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> forExpression,
            IEnumerable<TListItem> enumeratedItems,
            Property<TListItem> idExpression,
            Property<TListItem> displayExpression,
            Property<TListItem> titleExpression,
            object htmlAttributes) where TModel : class
        {
            return htmlHelper.SelectFor(
                forExpression,
                enumeratedItems,
                idExpression,
                displayExpression,
                titleExpression,
                htmlAttributes,
                true);
        }

        public static HtmlString SelectForWithBlankLine<TModel, TProperty, TListItem>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> forExpression,
            IEnumerable<TListItem> enumeratedItems,
            Property<TListItem> idExpression,
            Property<TListItem> displayExpression,
            Property<TListItem> titleExpression) where TModel : class
        {
            return htmlHelper.SelectForWithBlankLine(
                forExpression,
                enumeratedItems,
                idExpression,
                displayExpression,
                titleExpression,
                null);
        }

        public static HtmlString SelectForWithBlankLine<TModel, TProperty, TListItem>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> forExpression,
            IEnumerable<TListItem> enumeratedItems,
            Property<TListItem> idExpression,
            Property<TListItem> displayExpression) where TModel : class
        {
            return htmlHelper.SelectForWithBlankLine(
                forExpression,
                enumeratedItems,
                idExpression,
                displayExpression,
                displayExpression,
                null);
        }


	}
}
